package com.ruoyi.activiti.service.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.activiti.api.task.model.Task;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FormProperty;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.Page;
import com.ruoyi.activiti.domain.dto.ActTaskDTO;
import com.ruoyi.activiti.domain.dto.ActivitiHighLineDTO;
import com.ruoyi.activiti.domain.dto.HistoryProcessInstanceDTO;
import com.ruoyi.activiti.service.IActivitiHistoryService;
import com.ruoyi.activiti.service.IFormHistoryDataService;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.ISysUserService;

@Service
public class ActivitiHistoryServiceImpl implements IActivitiHistoryService {

    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskRuntime taskRuntime;
    @Autowired
    private IFormHistoryDataService formHistoryDataService;
    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ISysUserService sysUserService;
    /**
     *
     * @param pageDomain
     * @return
     */
    public Page<ActTaskDTO> getTasksDone(PageDomain pageDomain) {
        return this.getTasksDone(pageDomain, null);
    }

    @Override
    public Page<ActTaskDTO> getTasksDone(PageDomain pageDomain, String processDefinitionKey) {
        return this.getTasksDone(pageDomain, null, processDefinitionKey);
    }

    /**
     * 所有的流程实例，包括办结，未办结
     * @param pageDomain
     * @return
     */
    public Page<HistoryProcessInstanceDTO> getProcessInstances(PageDomain pageDomain, String processDefinitionKey) {
        return null;//this.getProcessInstances(pageDomain, null, processDefinitionKey);
    }
        /**
         *
         * @param pageDomain
         * @param processDefinitionKey
         * @return
         */
    public Page<ActTaskDTO> getTasksDone(PageDomain pageDomain, String type, String processDefinitionKey) {
        Page<ActTaskDTO> listAll = new Page<ActTaskDTO>();
        //获取流程实例 历史节点(全部)
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        List<HistoricProcessInstance> instances;
        if (type == null) {
            type = "all";
        }
        switch (type) {
            case "all":
                break;
            case "finished":
            case "done":
                query = query.finished();
                break;
            default:
                break;
        }

        if (processDefinitionKey != null) {
            query = query.processDefinitionKey(processDefinitionKey);
        }

        instances = query.list();

        for (HistoricProcessInstance instance : instances) {


            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instance.getId())
                    .orderByHistoricActivityInstanceEndTime()
                    .desc()
                    .list();
            for (HistoricActivityInstance i : list) {
                if (SecurityUtils.getUsername().equals(i.getAssignee())) {
                    if (i.getActivityType().equals("userTask") == false) {
                        continue;
                    }
                    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(i.getProcessInstanceId()).singleResult();

                    listAll.add(new ActTaskDTO(i, historicProcessInstance));
                    break; // 只跑一次
                }
            }
        }

        return listAll;
    }


    /**
     *
     * @param pageDomain
     * @param processDefinitionKey
     * @return
     */
    public Page<HistoryProcessInstanceDTO> getTasksDoneEx(PageDomain pageDomain, String processDefinitionKey) {
        Page<HistoryProcessInstanceDTO> listAll = new Page<HistoryProcessInstanceDTO>();
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery()
                .orderByHistoricActivityInstanceEndTime().activityType("userTask")
                .desc();
        List<HistoricActivityInstance> list = query
                .listPage((pageDomain.getPageNum() - 1) * pageDomain.getPageSize(), pageDomain.getPageSize());

        for (HistoricActivityInstance i : list) {

                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(i.getProcessInstanceId()).singleResult();

                listAll.add(new HistoryProcessInstanceDTO(i, historicProcessInstance));

        }
        listAll.setTotal(query.count());
        return listAll;
    }



    /**
     *
     * @param pageDomain
     * @param processDefinitionKey
     * @return
     */
    public Page<HistoryProcessInstanceDTO> getTaskDoneAsProcessInstance(PageDomain pageDomain, String type, String processDefinitionKey) {
        Page<HistoryProcessInstanceDTO> listAll = new Page<HistoryProcessInstanceDTO>();
        //获取流程实例 历史节点(全部)
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
        query = query.taskAssignee(SecurityUtils.getLoginUser().getUser().getUserName());
        List<HistoricActivityInstance> instances;
        switch (type) {
            case "all":
                break;
            case "finished":
            case "done":
                query = query.finished();
                break;
            default:
                break;
        }
        // TODO 已办有问题
        if (processDefinitionKey != null) {
            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).latestVersion();
            ProcessDefinition pd = processDefinitionQuery.singleResult();
            query = query.processDefinitionId(pd.getId());
        }
        instances = query.listPage((pageDomain.getPageNum() - 1) * pageDomain.getPageSize(), pageDomain.getPageSize());
        listAll.setTotal(instances.size());

        for (HistoricActivityInstance i : instances) {
            HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(i.getProcessInstanceId()).singleResult();
            listAll.add(new HistoryProcessInstanceDTO(i, instance, getObjectMap(i), sysUserService.selectUserByUserName(instance.getStartUserId())));
        }


        return listAll;
    }

    private Map<String, Object> getObjectMap(HistoricActivityInstance i) {
        final Map<String, Object> variables = new HashMap<>();
        if (i != null) {
            try {
                if (i.getExecutionId() != null) {
                	List<HistoricVariableInstance> historicVariableInstanceList = historyService.createHistoricVariableInstanceQuery().executionId(i.getExecutionId()).excludeVariableInitialization().list();
                	historicVariableInstanceList.forEach(item ->{
                		variables.put(item.getVariableName(), item.getValue());
                	});
                	//variables = runtimeService.getVariables(i.getExecutionId());
                }
            } catch (Exception e) {
                // TODO 为什么有时候没有数据？
            }
        }
        return variables;
    }


    @Override
    public List<String> formDataShow(String taskID) {
        Task task = taskRuntime.task(taskID);
/*  ------------------------------------------------------------------------------
            FormProperty_0ueitp2--__!!类型--__!!名称--__!!是否参数--__!!默认值
            例子：
            FormProperty_0lovri0--__!!string--__!!姓名--__!!f--__!!同意!!__--驳回
            FormProperty_1iu6onu--__!!int--__!!年龄--__!!s

            默认值：无、字符常量、FormProperty_开头定义过的控件ID
            是否参数：f为不是参数，s是字符，t是时间(不需要int，因为这里int等价于string)
            注：类型是可以获取到的，但是为了统一配置原则，都配置到
            */

        //注意!!!!!!!!:表单Key必须要任务编号一模一样，因为参数需要任务key，但是无法获取，只能获取表单key“task.getFormKey()”当做任务key
        UserTask userTask = (UserTask) repositoryService.getBpmnModel(task.getProcessDefinitionId())
                .getFlowElement(task.getFormKey());

        if (userTask == null) {
            return null;
        }
        List<FormProperty> formProperties = userTask.getFormProperties();
        List<String> collect = formProperties.stream().map(fp -> fp.getId()).collect(Collectors.toList());

        return collect;
    }

    @Override
    public Page<HistoryProcessInstanceDTO> getProcessInstances(PageDomain pageDomain, String type, String processDefinitionKey) {
        Page<HistoryProcessInstanceDTO> listAll = new Page<HistoryProcessInstanceDTO>();
        List<HistoricProcessInstance> instances;

        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();

        switch (type) {
            case "all":
                break;
            case "meCreated":
                query = query.startedBy(SecurityUtils.getUsername());
                break;
            case "startUserName":
                query = query.variableValueEquals("startUserName", "ry");
                break;
            case "finished":
            case "done":
                query = query.finished();
                break;
            default:
                break;
        }
        query = query.involvedUser(SecurityUtils.getLoginUser().getUser().getUserName());
        if (processDefinitionKey != null) {
            query = query.processDefinitionKey(processDefinitionKey);
        }
        if(pageDomain.getParameterMap()!=null){
        	for(String key :  pageDomain.getParameterMap().keySet()){
        		query.variableValueEqualsIgnoreCase(key, pageDomain.getParameterMap().get(key));
        	}
        }
        query = query.orderByProcessInstanceEndTime().desc();
        instances = query.listPage((pageDomain.getPageNum() - 1) * pageDomain.getPageSize(), pageDomain.getPageSize());
        long count = query.count();
        listAll.setTotal(count);

        for (HistoricProcessInstance instance : instances) {
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .activityType("startEvent")
                    .processInstanceId(instance.getId())
                    .list();
            for (HistoricActivityInstance i : list) {
                listAll.add(new HistoryProcessInstanceDTO(i,
                        instance, getObjectMap(null), sysUserService.selectUserByUserName(instance.getStartUserId())));
                break; // 只走一次
            }

        }
        return listAll;
    }

    public Page<ActTaskDTO> selectProcessDefinitionList(PageDomain pageDomain) {
        Page<ActTaskDTO> listAll = new Page<ActTaskDTO>();
        String instanceId = "1144c7c9-8490-11ec-80d0-2e6c84f2546c";
        //获取流程实例 历史节点(全部)
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        List<HistoricProcessInstance> instances = query.processDefinitionKey("receipt_form").list();

        for (HistoricProcessInstance instance : instances) {


            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instance.getId())
                    .list();
            for (HistoricActivityInstance i : list) {
                if (i.getActivityType().equals("startEvent")) {continue;}
                if (i.getActivityType().equals("endEvent")) {continue;}
                ActTaskDTO task = new ActTaskDTO();
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(i.getProcessInstanceId()).singleResult();
                task.setInstanceName(historicProcessInstance.getName());
                task.setId(i.getId());
                task.setName(i.getActivityName());
                task.setStatus("通过");
                listAll.add(task);
            }
        }

        return listAll;
    }

    @Override
    public ActivitiHighLineDTO gethighLine(String instanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId).singleResult();
        //获取bpmnModel对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
        //因为我们这里只定义了一个Process 所以获取集合中的第一个即可
        Process process = bpmnModel.getProcesses().get(0);
        //获取所有的FlowElement信息
        Collection<FlowElement> flowElements = process.getFlowElements();

        Map<String, String> map = new HashMap<>();
        for (FlowElement flowElement : flowElements) {
            //判断是否是连线
            if (flowElement instanceof SequenceFlow) {
                SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                String ref = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                map.put(ref + targetRef, sequenceFlow.getId());
            }
        }

        //获取流程实例 历史节点(全部)
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .list();
        //各个历史节点   两两组合 key
        Set<String> keyList = new HashSet<>();
        for (HistoricActivityInstance i : list) {
            for (HistoricActivityInstance j : list) {
                if (i != j) {
                    keyList.add(i.getActivityId() + j.getActivityId());
                }
            }
        }
        //高亮连线ID
        Set<String> highLine = new HashSet<>();
        keyList.forEach(s -> highLine.add(map.get(s)));


        //获取流程实例 历史节点（已完成）
        List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .finished()
                .list();
        //高亮节点ID
        Set<String> highPoint = new HashSet<>();
        listFinished.forEach(s -> highPoint.add(s.getActivityId()));

        //获取流程实例 历史节点（待办节点）
        List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .unfinished()
                .list();

        //需要移除的高亮连线
        Set<String> set = new HashSet<>();
        //待办高亮节点
        Set<String> waitingToDo = new HashSet<>();
        listUnFinished.forEach(s -> {
            waitingToDo.add(s.getActivityId());

            for (FlowElement flowElement : flowElements) {
                //判断是否是 用户节点
                if (flowElement instanceof UserTask) {
                    UserTask userTask = (UserTask) flowElement;

                    if (userTask.getId().equals(s.getActivityId())) {
                        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                        //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                        if (outgoingFlows != null && outgoingFlows.size() > 0) {
                            outgoingFlows.forEach(a -> {
                                if (a.getSourceRef().equals(s.getActivityId())) {
                                    set.add(a.getId());
                                }
                            });
                        }
                    }
                }
            }
        });

        highLine.removeAll(set);
        Set<String> iDo = new HashSet<>(); //存放 高亮 我的办理节点
        //当前用户已完成的任务
        List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
//                    .taskAssignee(SecurityUtils.getUsername())
                .finished()
                .processInstanceId(instanceId).list();

        taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));

        ActivitiHighLineDTO activitiHighLineDTO =new ActivitiHighLineDTO();
        activitiHighLineDTO.setHighPoint(highPoint);
        activitiHighLineDTO.setHighLine(highLine);
        activitiHighLineDTO.setWaitingToDo(waitingToDo);
        activitiHighLineDTO.setiDo(iDo);

        return activitiHighLineDTO;
    }
}
